﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using FSMtoCode.Types;
using System.Windows;

namespace FSMtoCode.Utils
{
    class XMLParser
    {
        AST ast; 

        public AST CreateASTbyXML(XmlTextReader XMLReader)
        {
            //Initialize the object
            ast = new AST();

            Boolean bFileNotCompatible = false;

            String sVarId = String.Empty;
            String sElement = String.Empty;           

            if (XMLReader.Name != "xml")
                bFileNotCompatible = true;

            XMLReader.Read(); XMLReader.Read();

            if (XMLReader.Name != "dia:diagram")
                bFileNotCompatible = true;

            if (!bFileNotCompatible)
            {
                while (XMLReader.Read())
                {
                    if (XMLReader.Name.Equals("dia:object"))
                    {
                        switch (XMLReader.GetAttribute("type"))
                        {
                            //Final or Initial State
                            case "UML - State Term": SaveStatesTermInf(XMLReader, sElement); break;
                            case "UML - State": SaveStatesInf(XMLReader); break;
                            case "UML - Transition": SaveTransitionInf(XMLReader); break;
                        }
                    }
                }
            }

            return ast; 

        }//ReadFile

        private void SaveStatesTermInf(XmlTextReader XMLReader, String sElement)
        {
            FSMStateTerm stateTerm = new FSMStateTerm();

            //Save state's id
            stateTerm.Id = XMLReader.GetAttribute("id");

            //Search XML util find the attribute is_final
            while (!sElement.Equals("is_final"))
            {
                XMLReader.ReadToFollowing("dia:attribute");
                sElement = XMLReader.GetAttribute("name");
            }

            //Save value of is_final and put it in the list
            XMLReader.ReadToFollowing("dia:boolean");
            XMLReader.MoveToFirstAttribute();
            stateTerm.IsFinal = Convert.ToBoolean(XMLReader.Value);

            ast.SaveStateTerm(stateTerm);
        } //SaveStatesTermInf

        private void SaveStatesInf(XmlTextReader XMLReader)
        {
            FSMState state = new FSMState();

            //Save state's id
            state.Id = XMLReader.GetAttribute("id");

            String sAtributeType = "text";
            state.Name = GetElementInfFromXML(XMLReader, sAtributeType);

            sAtributeType = "entry_action";
            state.EntryAction = GetElementInfFromXML(XMLReader, sAtributeType);

            sAtributeType = "do_action";
            state.DoAction = GetElementInfFromXML(XMLReader, sAtributeType);

            sAtributeType = "exit_action";
            state.ExitAction = GetElementInfFromXML(XMLReader, sAtributeType);

            //Save State in the list
            ast.SaveState(state);
        }

        private void SaveTransitionInf(XmlTextReader XMLReader)
        {
            Boolean bDirectionInverted = false;
            String sElementName = String.Empty;

            FSMTransition transition = new FSMTransition();

            //Save state's id
            transition.Id = XMLReader.GetAttribute("id");

            //Save state infs
            String sAtributeType = "trigger";
            transition.Trigger = GetElementInfFromXML(XMLReader, sAtributeType);

            Boolean isOK = AddEventParam(transition,1);

            //Replace the trigger Name(params) for Name 
            transition.Trigger = SubTriggerName(transition.Trigger);
            
            sAtributeType = "action";
            transition.Action = GetElementInfFromXML(XMLReader, sAtributeType);

            isOK = AddEventParam(transition,2);
            
            //Replace the action Name(params) for Name 
            transition.Action = SubTriggerName(transition.Action);

            sAtributeType = "guard";
            transition.Guard = GetElementInfFromXML(XMLReader, sAtributeType);

            sAtributeType = "direction_inverted";

            //Search XML util find the attribute 
            while (!sElementName.Equals(sAtributeType))
            {
                XMLReader.ReadToFollowing("dia:attribute");
                sElementName = XMLReader.GetAttribute("name");
            }

            //Gets the value of direction_inverted property
            XMLReader.ReadToFollowing("dia:boolean");
            XMLReader.MoveToFirstAttribute();
            transition.DirectionInverted = Convert.ToBoolean(XMLReader.Value);

            //Gets the connections between states 
            XMLReader.ReadToFollowing("dia:connection");

            if (!bDirectionInverted)
                transition.ConnecFrom = XMLReader.GetAttribute("to").Replace("#", String.Empty);
            else
                transition.ConnecTo = XMLReader.GetAttribute("to").Replace("#", String.Empty);

            XMLReader.ReadToFollowing("dia:connection");

            ////Nao preciso de repetir esse bloco - colocar no bloco de cima/////
            if (!bDirectionInverted)
                transition.ConnecTo = XMLReader.GetAttribute("to").Replace("#", String.Empty);
            else
                transition.ConnecFrom = XMLReader.GetAttribute("to").Replace("#", String.Empty);

            ast.SaveTransition(transition);

        }//SaveTransitionInf

        private String SubTriggerName(String sTriggerName)
        {
            //Substring pos 0 to ( 
            if (sTriggerName.IndexOf("(") != -1)            
                return sTriggerName.Substring(0,sTriggerName.IndexOf("("));            
            else
                return sTriggerName;
        }

        private bool AddEventParam(FSMTransition transition, int iTypeList)
        {
            String sVarType = String.Empty;
            String sVarName = String.Empty;
            String sEventName = String.Empty; 
         
            if (iTypeList == 1)
               sEventName = transition.Trigger;
            else if (iTypeList == 2)
               sEventName = transition.Action;            

            int c = 0;
            while(c < sEventName.Length)
            {
                String sCarac = Convert.ToString(sEventName.ElementAt(c));
                try
                { 
                    if (sCarac.Equals("("))
                    {                     
                        //Go foward 
                        sCarac = Convert.ToString(sEventName.ElementAt(++c));

                        if (sCarac.Equals("") || sCarac.Equals(")"))
                            return false;
                        else
                        {
                            while (!sCarac.Equals(",") && !sCarac.Equals(")"))
                            {
                                switch (sCarac)
                                {
                                    case "i": sVarType = "int"; break;
                                    case "d": sVarType = "double"; break;
                                    case "b": sVarType = "Boolean"; break;
                                    case "l": sVarType = "long"; break;
                                    case "s": sVarType = "string"; break;                                    
                                }

                                if (sCarac.Equals(":"))
                                {
                                    //Go foward 
                                    sCarac = Convert.ToString(sEventName.ElementAt(++c));
                                    sVarName = "";
                                    while (!sCarac.Equals(",") && !sCarac.Equals(")"))
                                    {
                                        sVarName = sVarName + sCarac;

                                        //Go foward 
                                        sCarac = Convert.ToString(sEventName.ElementAt(++c));
                                    }

                                    if(iTypeList == 1)
                                        transition.TriggerParam.Add(sVarType + " " + sVarName);
                                    else if(iTypeList == 2)
                                        transition.ActionParam.Add(sVarType + " " + sVarName);
                                }

                                if (!sCarac.Equals(")"))                                
                                  sCarac = Convert.ToString(sEventName.ElementAt(++c));                                
                            }
                        }                       
                     }                   
                }//try
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message);
                }
                c++;               
            }//while
            return true;            
        }

        private string GetElementInfFromXML(XmlTextReader XMLReader, String sAtributeType)
        {
            String sElementName = String.Empty;

            //Search XML util find the attribute text
            while (!sElementName.Equals(sAtributeType))
            {
                XMLReader.ReadToFollowing("dia:attribute");
                sElementName = XMLReader.GetAttribute("name");
            }

            //Go to 'dia:string' attribute and reads the string value     
            XMLReader.ReadToFollowing("dia:string");

            //Remove the '#' from XML text
            return XMLReader.ReadString().Replace("#", String.Empty);
        }

    }
}